// 注意 std::env 必须引入进来
use std::{env, fs, process};
use std::error::Error;

// 定义一个查询的配置结构，用来结构化配置参数
#[derive(Debug)]
pub struct QueryConfig {
    query_file : String,
    query_str : String,
}

impl QueryConfig {
    // 实现 create 方法，主要提供参数验证，生成配置对象
    pub fn create() ->Result<QueryConfig, &'static str> {
        let args: Vec<String> = env::args().collect();
        // 做一个验证，检查一下args 的参数个数应该恰巧 = 3 过长或者过短都有问题
        if 3 != args.len() {
            // panic!("参数错误，格式应该是: {query_str} {query_file}");
            return Err("参数错误，格式应该是: query_str query_file")
        }

        Ok(QueryConfig {
            // 这里要用 clone() 函数否则 args 很快就出了作用域。
            query_str: args[1].clone(),
            query_file: args[2].clone(),
        })
    }
}

// 运行函数
pub fn run(conf:QueryConfig) -> Result<(), Box<dyn Error>>{
    //expect("Something went wrong reading the file.")
    let content = fs::read_to_string(conf.query_file)?;
    // println!("缺少具体的run 函数内容  {}", content);
    let result_vec = search(&conf.query_str, &content);

    eprintln!("Query string : {},  Match line : {:?}", conf.query_str, result_vec);
    Ok(())
}


/// 这个函数的功能用于查找 search_content 出现 query_str 的哪些行。
/// 因为传入了两个参数，这是后返回的声明周期要明确出是哪个参数的声明周期
/// 通过 <'a> 来进行声明，返回的声明周期同 search_content 的声明周期一致即可。
fn search<'a >(query_str:&str, search_content:&'a str) -> Vec<&'a str> {
    // 将查询字符串转成小写：
    let query_str = query_str.to_lowercase();
    // vec!["lin","hai"]
    let mut resutl_vec : Vec<&str> = Vec::new();
    // 按行遍历字符串
    for line in search_content.lines() {
        if line.to_lowercase().contains(&query_str) {
            resutl_vec.push(line);
        }
    }
    resutl_vec
}

// 添加一个测试模块通过TDD的方式进行开发。
#[cfg(test)]
mod test {
    // 引入全部类库，用于测试，这是一种简单的饮用方式，通常在测试中这样引入。
    use super::*;

    // 建立一个测试方法
    #[test]
    fn one_result() {
        // 定义查询值
        let query_str = "Lin";
        let file_content = "\
When typed Hello world,
that means Lin Hai learn language of rust.
but rust is not friendly to him,
so Lin Hai felt very horror.
        ";
        assert_eq!(
            // 理论上查询 Lin 应该返回的 Vec
            vec!["that means Lin Hai learn language of rust.", "so Lin Hai felt very horror."],
            // 执行查询操作
            search(query_str, file_content)
        ) ;
    }

    #[test]
    fn two_result() {
        // 定义查询值
        let query_str = "lIn";
        let file_content = "\
When typed Hello world,
that means Lin Hai learn language of rust.
but rust is not friendly to him,
so Lin Hai felt very horror.
        ";
        assert_eq!(
            // 理论上查询 Lin 应该返回的 Vec
            vec!["that means Lin Hai learn language of rust.", "so Lin Hai felt very horror."],
            // 执行查询操作
            search(query_str, file_content)
        ) ;
    }
}